unit uAppConfig;

interface

uses
  SysUtils, Classes, Graphics, Windows, Variants, uDZSysUtils, uDZPersistent, uDZConfig,
  uCxtTypes, uDZBase64, uAppCmdLineParams, uAppConst, uGxtConfigUtils, uGxtCity;

type
  TUserPrefColumn = class(TDzPersistent)
  private
    fFieldName: string;
    fWidth: Integer;
  published
    property FieldName: string read fFieldName write fFieldName;
    property Width: Integer read fWidth write fWidth;
  end;

  TUserPrefColumns = class(TDzPersistentList)
  private
    function GetItems(Index: Integer): TUserPrefColumn;
    procedure SetItems(Index: Integer; const Value: TUserPrefColumn);
  public
    constructor Create; reintroduce;
    function Add: TUserPrefColumn;
    property Items[Index: Integer]: TUserPrefColumn read GetItems write SetItems; default;
  end;
  
  TAppConfig = class(TDzPersistent)
  private
    CfgFile: string;
    fVersion: Integer;
    fSkinFile: string;
    fSavedLogins: TSavedLogins;
    fUsername: string;
    fPassword: string;
    fSaveLogin: Boolean;
    fAutoLogin: Boolean;
    fFont: Graphics.TFont;
    fPersonalGridColumns: TUserPrefColumns;
    fLocPersonGridColumns: TUserPrefColumns;
    fShareGridColumns: TUserPrefColumns;
    fWebShareGridColumns: TUserPrefColumns;
    fPosTrackGridColumns: TUserPrefColumns;
    fCtl3D: Boolean;
    fServerPort: Integer;
    fServerIP: AnsiString;
    procedure SetFont(const Value: Graphics.TFont);
    procedure SetLocPersonGridColumns(const Value: TUserPrefColumns);
    procedure SetPersonalGridColumns(const Value: TUserPrefColumns);
    procedure SetPosTrackGridColumns(const Value: TUserPrefColumns);
    procedure SetShareGridColumns(const Value: TUserPrefColumns);
    procedure SetWebShareGridColumns(const Value: TUserPrefColumns);
  public
    constructor Create; override;
    destructor Destroy; override;
    procedure AdjustSavedLogins;
  published
    property Version: Integer read fVersion write fVersion;
    property ServerIP: AnsiString read fServerIP write fServerIP;
    property ServerPort: Integer read fServerPort write fServerPort;
    property SavedLogins: TSavedLogins read fSavedLogins;
    property Username: string read fUsername write fUsername;
    property Password: string read fPassword write fPassword;
    property SaveLogin: Boolean read fSaveLogin write fSaveLogin;
    property AutoLogin: Boolean read fAutoLogin write fAutoLogin;
    property Font: Graphics.TFont read fFont write SetFont;
    property Ctl3D: Boolean read fCtl3D write fCtl3D;
    property SkinFile: string read fSkinFile write fSkinFile;
    property PersonalGridColumns: TUserPrefColumns
      read fPersonalGridColumns write SetPersonalGridColumns;

    property LocPersonGridColumns: TUserPrefColumns
      read fLocPersonGridColumns write SetLocPersonGridColumns;

    property ShareGridColumns: TUserPrefColumns
      read fShareGridColumns write SetShareGridColumns;

    property WebShareGridColumns: TUserPrefColumns
      read fWebShareGridColumns write SetWebShareGridColumns;

    property PosTrackGridColumns: TUserPrefColumns
      read fPosTrackGridColumns write SetPosTrackGridColumns;
  end;

var
  AppConfig: TAppConfig;
  AreaList: TProvinceList;

procedure LoadConfig;
procedure SaveConfig;

implementation

function StringEncrypt(const S: AnsiString): AnsiString;
var
  pch: PAnsiChar;
  i: Integer;
begin
  SetString(Result, PAnsiChar(S), Length(S));
  pch := PAnsiChar(Result);
  for i := 0 to Length(Result) - 1 do pch[i] := AnsiChar(not PByte(pch + i)^);
  Result := Base64Encode(Result);
end;

function StringDecrypt(const S: AnsiString): AnsiString;
var
  pch: PAnsiChar;
  i: Integer;
begin
  Result := Base64Decode(S);
  pch := PAnsiChar(Result);
  for i := 0 to Length(Result) - 1 do pch[i] := AnsiChar(not PByte(pch + i)^);
end;

function Base64Cnt(const S: AnsiString): Integer;
var
  i: Integer;
  Temp: AnsiString;
begin
  Result := 0;
  Temp := S;
  while Length(Temp) mod 4 = 0 do
  begin
    for i := 1 to Length(Temp) do
      if not (Temp[i] in ['A'..'Z', 'a'..'z', '0'..'9', '+', '=', '/']) then Exit;
    Temp := StringDecrypt(Temp);
    Inc(Result);
  end;
end;

function StringDecryptN(const S: AnsiString): AnsiString; overload;
var
  i: Integer;
begin
  Result := S;
  while Length(Result) mod 4 = 0 do
  begin
    for i := 1 to Length(Result) do
      if not (Result[i] in ['A'..'Z', 'a'..'z', '0'..'9', '+', '=', '/']) then Exit;
    Result := StringDecrypt(Result);
  end;
end;

function StringDecryptN(const S: AnsiString; N: Integer): AnsiString; overload;
var
  i: Integer;
begin
  Result := S;
  for i := 0 to N - 1 do
    Result := StringDecrypt(Result);
end;

procedure CorrectUserNamePassword(var UserName, Password: AnsiString);
var
  C1, C2: Integer;
begin
  if UserName = '' then Exit;
  if Password = '' then 
  begin
    UserName := StringDecryptN(UserName);
    Exit;
  end;
  C1 := Base64Cnt(UserName);
  C2 := Base64Cnt(Password);
  if C1 > C2 then C1 := C2;
  UserName := StringDecryptN(UserName, C1);
  Password := StringDecryptN(Password, C1);
  
end;

procedure LoadAreas;
var
  FileName: string;
  Stream: TStream;
begin
  FileName := GetAppDataPath + '\' + CWorkDirectory + '\AreaList.xml';
  if FileExists(FileName) then
  try
    AreaList.List.LoadFromFile(FileName, afXML);
    AreaList.FixCityProvinceReference;
    Exit;
  except

  end;
  Stream := TResourceStream.Create(HInstance, 'arealist', 'xml');
  try
    AreaList.List.LoadFromStream(Stream, afXML);
  except
  end;
  Stream.Free;
end;

procedure LoadConfig;
var
  i: Integer;
  OldCfgFile: string;
begin
  with AppConfig do
  try
    if FileExists(CfgFile) then
      LoadFromFile(CfgFile, afXML, [aoEnumName])
    else begin
      OldCfgFile := GetAppDataPath + '\' + CWorkDirectory + '\cxtclient.conf';
      if FileExists(OldCfgFile) then
        LoadFromFile(OldCfgFile, afXML, [aoEnumName]);
      fFont.Size := 11;
      fFont.Name := 'Tahoma';
    end;
    if Version < 5 then
    begin
      fPersonalGridColumns.Clear;
      fLocPersonGridColumns.Clear;
      fShareGridColumns.Clear;
      fWebShareGridColumns.Clear;
    end;
  except
    fFont.Size := 11;
    fFont.Name := 'Tahoma';
  end;
  with AppConfig do
  begin
    fFont.Orientation := 0;
    fFont.Style := fFont.Style - [fsItalic, fsUnderline, fsStrikeOut];
    Ctl3D := False;
    if Version >= 6 then
    begin
      if fUsername <> '' then fUsername := StringDecrypt(fUserName);
      if fPassword <> '' then fPassword := StringDecrypt(fPassword);
      for i := 0 to SavedLogins.Count - 1 do
      with SavedLogins.Items[i] do
      begin
        if UserName <> '' then UserName := StringDecrypt(UserName);
        if Password <> '' then Password := StringDecrypt(Password);
      end;
    end;
  end;
  LoadAreas;
end;

procedure SaveAreaList;
begin
  if Assigned(AreaList) then
  begin
    ForceDirectories(GetAppDataPath + '\' + CWorkDirectory);
    AreaList.List.SaveToFile(GetAppDataPath + '\' +
      CWorkDirectory + '\AreaList.xml', afXML);
  end;
end;

procedure SaveConfig;
var
  i: Integer;
begin
  AppConfig.Version := 6;
  AppConfig.AdjustSavedLogins;
  with AppConfig do
  try
    if fUsername <> '' then fUsername := StringEncrypt(fUserName);
    if fPassword <> '' then fPassword := StringEncrypt(fPassword);
    for i := 0 to SavedLogins.Count - 1 do
    begin
      SavedLogins.Items[i].UserName := StringEncrypt(SavedLogins.Items[i].UserName);
      SavedLogins.Items[i].Password := StringEncrypt(SavedLogins.Items[i].Password);
    end;
    ForceDirectories(GetAppDataPath + '\' + CWorkDirectory);
    SaveToFile(CfgFile, afXML, [aoNoWriteNullStr, aoEnumName]);
  except
  end;
  SaveAreaList;
end;

{ TAppConfig }

procedure TAppConfig.AdjustSavedLogins;
var
  UserInfo: TUserInfo;
begin
  UserInfo := SavedLogins.GetLogin(Username);
  if not Assigned(UserInfo) then UserInfo := SavedLogins.Add
  else SavedLogins.Move(UserInfo, 0);
  with UserInfo do
  begin
    Username := Self.Username;
    Password := Self.Password;
  end;
end;

constructor TAppConfig.Create;
begin
  inherited;
  fFont := Graphics.TFont.Create;
  fSavedLogins := TSavedLogins.Create;
  fPersonalGridColumns := TUserPrefColumns.Create;
  fLocPersonGridColumns := TUserPrefColumns.Create;
  fShareGridColumns := TUserPrefColumns.Create;
  fWebShareGridColumns := TUserPrefColumns.Create;
  fPosTrackGridColumns := TUserPrefColumns.Create;
  fSaveLogin := True;
  CfgFile := GetAppDataPath + '\' + CWorkDirectory + '\client.conf';
end;

destructor TAppConfig.Destroy;
begin
  FreeAndNil(fSavedLogins);
  FreeAndNil(fFont);
  FreeAndNil(fPersonalGridColumns);
  FreeAndNil(fLocPersonGridColumns);
  FreeAndNil(fShareGridColumns);
  FreeAndNil(fWebShareGridColumns);
  FreeAndNil(fPosTrackGridColumns);
  inherited;
end;

procedure TAppConfig.SetFont(const Value: Graphics.TFont);
begin
  Font.Assign(Value);
end;

procedure TAppConfig.SetLocPersonGridColumns(const Value: TUserPrefColumns);
begin
  fLocPersonGridColumns.Assign(Value);
end;

procedure TAppConfig.SetPersonalGridColumns(const Value: TUserPrefColumns);
begin
  fPersonalGridColumns.Assign(Value);
end;

procedure TAppConfig.SetPosTrackGridColumns(const Value: TUserPrefColumns);
begin
  fPosTrackGridColumns.Assign(Value);
end;

procedure TAppConfig.SetShareGridColumns(const Value: TUserPrefColumns);
begin
  fShareGridColumns.Assign(Value);
end;

procedure TAppConfig.SetWebShareGridColumns(const Value: TUserPrefColumns);
begin
  fWebShareGridColumns.Assign(Value);
end;

{ TUserPrefColumns }

function TUserPrefColumns.Add: TUserPrefColumn;
begin
  Result := TUserPrefColumn(inherited Add);
end;

constructor TUserPrefColumns.Create;
begin
  inherited Create(TUserPrefColumn);
end;

function TUserPrefColumns.GetItems(Index: Integer): TUserPrefColumn;
begin
  Result := TUserPrefColumn(inherited Items[Index]);
end;

procedure TUserPrefColumns.SetItems(Index: Integer; const Value: TUserPrefColumn);
begin
  inherited Items[Index] := Value;
end;

initialization
  AppConfig := TAppConfig.Create;
  AreaList := TProvinceList.Create;
  
finalization
  AppConfig.Free;
  AreaList.Free;
    
end.
